#include <windows.h>
#include <pthread\cppthread.h>

#include <dice\dice.h>

#include "gameEngine.h"
#include "actor.h"
#include "roger.h"
#include "mainwin.h"

#include <cstdio>

#define fps_limit(ms)    1000/ms
#define INTERFACE_LIMIT  60
#define GAMEENGINE_LIMIT 40

gameEngine* GE;

using namespace std;

void * neutralAIThread( void * );
void * game_engine_thread( void* );

void * game_engine_thread( void* ){

    GE->getMap()->setCell(CELL_OBSTACLE,4,4);

    mapObject mo;
    mo.setType( MOB_CHAR );

    mo.setCoord( 20,20 );
    GE->getMap()->addObject( new mapObject(&mo) );

    actor* act;

    GE->getMap()->neutralMutex.lock();
        //act = new actor();
        act = new AI_roger();
        act->setCoord(10+D(5),20+D(10));
        GE->getMap()->addObject( act );
    GE->getMap()->neutralMutex.unlock();

    cppthread_t NAIThread(neutralAIThread);

    clock_t frameTime = clock();

    printf("GET: Init OK\n");

    while(1){
        clock_t stack;
        if( (stack = clock() - frameTime) < fps_limit(GAMEENGINE_LIMIT) ){
            printf("GET: Limit %d\n",(int)stack);
            Sleep( fps_limit(GAMEENGINE_LIMIT) - stack );
            printf("GET: Endlimit\n");
        }
        frameTime = clock();
        printf("GET: GotLim\n");
        if( D(GAMEENGINE_LIMIT) == 1 ){
            printf("GET: Add Roger\n");
            coord_t coord;
            coord.X_coord = 10+D(5);
            coord.Y_coord = 20+D(10);
            cell_t* destCell = GE->getMap()->getCell(coord);
            if( !( getStatus( CELL_OBSTACLE, *destCell ) || getStatus( CELL_OCCUPIED, *destCell ) ) ){
                GE->getMap()->neutralMutex.lock();
                    act = new AI_roger();
                    act->setCoord(coord);
                    GE->getMap()->addObject( act );
                GE->getMap()->neutralMutex.unlock();
            }
        }

        printf("GET: In>exec\n");
        GE->execActions();
        printf("GET: Out>exec\n");
    };

    return NULL;
}

void * neutralAIThread( void * ){

    actor* act;

    printf("NAI: Init OK\n");
    while(1){
        GE->getMap()->neutralMutex.lock();
            GE->NActorsMutex.lock();
                printf("NAI: Explore act\n");
                while( (act = GE->getNextNActorW()) ){
                    act->exec_AI();
                }
            GE->NActorsMutex.unlock();
        GE->getMap()->neutralMutex.unlock();

        printf("NAI: wait\n");
        GE->NActorsCond.wait();
    }

    return NULL;

}

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{

    pthread_win32_process_attach_np();

    DINIT

    MSG msg;
    bool quit = false;

    win = new mainWin();
    GE = new gameEngine();

    clock_t frameTime = clock();

    cppthread_t* ge_th = new cppthread_t(game_engine_thread);

    win->setName("Rogers: 1");

    while( !quit ){
        clock_t stack;
        if( (stack = clock() - frameTime) < fps_limit(INTERFACE_LIMIT) ){
            Sleep( fps_limit(INTERFACE_LIMIT) - stack );
        }
        frameTime = clock();
		while (PeekMessage(&msg,NULL,0,0,PM_REMOVE)){
			if (msg.message==WM_QUIT){
				quit = true;
			}else{
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}
        if (win){
            if (win->isActive()){
                win->elEventExec();
                win->display();
                win->updateMgr();
            }
        }
    }

    delete ge_th;

    pthread_win32_process_detach_np();

    return EXIT_SUCCESS;
}
